### adsb_parser/parser.py

import os
import sys
import subprocess
import pyshark
import csv
from structures import ASSAP_OUTPUT_FILE

def resource_path(relative_path):
    """
    获取资源文件的绝对路径，兼容 PyInstaller 打包和开发环境
    """
    if hasattr(sys, '_MEIPASS'):
        # PyInstaller 打包后的临时路径
        return os.path.join(sys._MEIPASS, relative_path)
    return os.path.join(os.path.abspath("."), relative_path)

# # 明确指定 TShark 路径（适配 PyCharm 无法读取系统环境变量的问题）
# TSHARK_PATH = 'D:\\Program Files\\Wireshark\\tshark.exe'
# # 获取动态路径
# tshark_path = resource_path("tshark.exe")

def extract_payloads(pcap_path, udp_port=62325):
    capture = pyshark.FileCapture(
        pcap_path,
        display_filter=f"udp.port == {udp_port} and not icmp",
        use_json=True,
        tshark_path=resource_path(os.path.join("wireportable", "tshark.exe")) # 获取动态路径
    )
    for packet in capture:
        try:
            hex_payload = packet.udp.payload.replace(":", "")
            raw_bytes = bytes.fromhex(hex_payload)
            if len(raw_bytes) >= 11760:
                yield raw_bytes[:11760]
        except Exception as e:
            print("提取失败:", e)

def write_csv(records, output_file):
    with open(output_file, 'w', newline='') as csvfile:
        writer = csv.writer(csvfile)

        # 添加字段名（表头）
        writer.writerow([
            "FrameHeader",
            "FrameNumber",
            "OwnshipQualifiedForAIRB",
            "OwnshipQualifiedForVSA",
            "AIRB_Status",
            "VSA_Status",
            "TargetsNum",
            "TargetsNumOnlyTCAS",
            "TargetsNumAirborne",
            "TargetsNumSurface",

            # "Target_BinTime",
            # "Target_Num",
            # "Target_UniqueID",
            # "Target_Type",
            # "Target_TCASAlertStatus",
            # "Target_FlightID",
            # "Target_EmitterCat",
            # "Target_EmergencyStatus",
            # "Target_AirGroundStatus",
            # "Target_X",
            # "Target_Y",
            # "Target_Z",
            # "Target_Lat",
            # "Target_Lon",
            # "Target_Alt",
            # "Target_Range",
            # "Target_Bearing",
            # "Target_RelAlt",
            # "Target_NS_Vel",
            # "Target_EW_Vel",
            # "Target_Track_HDG_TRK",
            # "Target_GroundSpeed",
            # "Target_DGS",
            # "Target_ValidityTrafficDir",
            # "Target_VerticalSense",
            # "Target_TCASTag",
            # "Target_QualifiedForVSA",
            # "Target_NACP",
            # "Target_NACV",
            # "Target_SelectionMark",
            # "Target_SelectionVSAMark",
            # "Target_RelAltValidity",
            # "Target_BearingValidity",
            # "Target_FunctionTest",
            # "Target_VerticalSpeedType",
            # "Target_GeoVS_Valid",
            # "Target_BaroVS_Valid",
            # "Target_SensitivityLevel",
            # "Target_VerticalSpeed",
            # "Target_VelocityValidity",

            "Ownship_SensitivityLevel",
            "Ownship_ADSB_OUT_mode",
            "Ownship_ADSB_IN_mode",
            "Ownship_AltitudeSelect",
            "Ownship_IntruderAltitude",

            "Fault_ACAS_ADSB_OUT_FAULT_EICAS",
            "Fault_ACAS_ADSB_IN_SYSTEM_FAULT",
            "Fault_ACAS_VSA_QUALIFIED",
            "Fault_ACAS_ADSB_IN_ENABLED",
            "Fault_COMM_TCAS",
            "Fault_COMM_FPGA",
            "Fault_COMM_IO",
            "Fault_ICAO_Address",
            "Fault_TMP_Mode",
            "Fault_Hori_Pos",
            "Fault_Vert_Pos",
            "Fault_Not_Qualified_AIRB",
            "Fault_ADSB_OUT_Type0",
            "Fault_Tx_Top",
            "Fault_Tx_Bot",
            "Fault_Rx_Top",
            "Fault_Rx_Bot",
            "Fault_Impedance_Top",
            "Fault_Impedance_Bot",
            "Fault_Self_TxRx_Top",
            "Fault_Self_TxRx_Bot",
            "Fault_Broadcast_Monitor",

            "Display_ND_TFC_FO",
            "Display_ND_TFC_Capt",
            "Display_HSI_TFC_FO",
            "Display_HSI_TFC_Capt",
            "SW_Number",

            "ADSB_MSG_Validity_Num",
            "FrameTail"
        ])

        # 写入每条数据
        for record in records:
            writer.writerow(record)

def parse_packets(pcap_path):
    all_records = []
    for payload in extract_payloads(pcap_path):
        try:
            parsed = ASSAP_OUTPUT_FILE.parse(payload)
            all_records.append(parsed)
        except Exception as e:
            print("解析失败:", e)
    return all_records

def flatten_for_export(parsed_record):
    return [
        f"0x{parsed_record.FrameHeader:08X}", # :08X 表示用 8 个十六进制位补足（大写字母）；如果你想用小写：:08x
        parsed_record.FrameNumber,
        parsed_record.ownship_qualified_for_airb,
        parsed_record.ownship_qualified_for_vsa,
        parsed_record.airb_status,
        parsed_record.vsa_status,
        parsed_record.targets_num,
        parsed_record.targets_num_only_tcas,
        parsed_record.targets_num_airborne,
        parsed_record.targets_num_surface,
        # parsed_record.targets[0].bintime,
        # parsed_record.targets.num,
        # parsed_record.targets.target_unique_id,
        # parsed_record.targets.type,
        # parsed_record.targets.tcas_alert_status,
        # parsed_record.targets.flight_id,
        # parsed_record.targets.emitter_cat,
        # parsed_record.targets.emergency_priority_status,
        # parsed_record.targets.air_gnd_status,
        # parsed_record.targets.x,
        # parsed_record.targets.y,
        # parsed_record.targets.z,
        # parsed_record.targets.lat,
        # parsed_record.targets.lon,
        # parsed_record.targets.alt,
        # parsed_record.targets.range,
        # parsed_record.targets.bearing,
        # parsed_record.targets.relative_alt,
        # parsed_record.targets.ns_v,
        # parsed_record.targets.ew_v,
        # parsed_record.targets.track_hdg_trk,
        # parsed_record.targets.ground_speed,
        # parsed_record.targets.dgs,
        # parsed_record.targets.alidity_flag_traffic_dir,
        # parsed_record.targets.vertical_sense,
        # parsed_record.targets.tcas_tag,
        # parsed_record.targets.traffic_qualified_for_vsa,
        # parsed_record.targets.nacp,
        # parsed_record.targets.nacv,
        # parsed_record.targets.selection_mark,
        # parsed_record.targets.selection_vsa_mark,
        # parsed_record.targets.relative_alt_validity,
        # parsed_record.targets.bearing_validity,
        # parsed_record.targets.function_test_active,
        # parsed_record.targets.vertical_speed_type,
        # parsed_record.targets.geo_vertical_speed_validity,
        # parsed_record.targets.baro_vertical_speed_validity,
        # parsed_record.targets.intruder_sensitivity_level,
        # parsed_record.targets.vertical_speed,
        # parsed_record.targets.ew_ns_velocity_validity,
        parsed_record.ownship_status_infomation.Sensitivity_Level_Control,
        parsed_record.ownship_status_infomation.ADSB_OUT_mode,
        parsed_record.ownship_status_infomation.ADSB_IN_mode,
        parsed_record.ownship_status_infomation.Altitude_Select.altitude_select,
        parsed_record.ownship_status_infomation.Altitude_Select.intruder_altitude,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.MA51_ACAS_ADSB_OUT_FAULT_EICAS,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.MA51_ACAS_ADSB_IN_SYSTEM_FAULT,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.MA51_ACAS_VSA_OWNSHIP_QUALIFIED,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.MA51_ACAS_ADSB_IN_ENABLED_OSS,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.ABNORMAL_INPUT_COMM_OF_TCAS,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.ABNORMAL_INPUT_COMM_OF_FPGA,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.ABNORMAL_INPUT_COMM_OF_IO,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.ICAO_Address_Fault,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.TMP_Mode_Control_Fault,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.Ownship_Hori_Position_Fault,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.Ownship_Vert_Position_Fault,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.Ownship_Not_Qualified_for_AIRB,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.ADSB_OUT_Type_0_Trigged,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.Top_RF_TX_Channel_Fault,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.Bot_RF_TX_Channel_Fault,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.Top_RF_RX_Channel_Fault,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.Bot_RF_RX_Channel_Fault,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.Top_Ant_Impedance_Fault,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.Bot_Ant_Impedance_Fault,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.Top_Self_TX_RX_Fault,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.Bot_Self_TX_RX_Fault,
        parsed_record.ownship_status_infomation.ADSB_Fault_Status.Broadcast_Monitoring_Fault,
        parsed_record.ownship_status_infomation.Display_Mode.ND_TFC_ADSB_Selection_Fo,
        parsed_record.ownship_status_infomation.Display_Mode.ND_TFC_ADSB_Selection_Capt,
        parsed_record.ownship_status_infomation.Display_Mode.HSI_TFC_ADSB_Selection_Fo,
        parsed_record.ownship_status_infomation.Display_Mode.HSI_TFC_ADSB_Selection_Capt,
        parsed_record.ownship_status_infomation.sw_number,
        parsed_record.ADSB_MSG_Validity_Num,
        f"0x{parsed_record.FrameTail:08X}"
    ]

def export_all(pcap_path):
    parsed_records = parse_packets(pcap_path)
    print(f"共解析 {len(parsed_records)} 个数据包")

    flat_rows = [flatten_for_export(r) for r in parsed_records]
    write_csv(flat_rows, "adsb_output.csv")
    print("CSV导出完毕")
